<template>
    <div class="simulationPlatform-container">
        <MCard>
            <template #header>
              <div class="flex justify-between items-center w-100%">    
                <div class="simulationPlatform-header">
                    <span>宿主机信息</span>
                </div>
              </div>
            </template>
            <div class="host-container grid grid-cols-4 gap-10px m-t-20px">
               <div class="deployedNodeItem" v-for="(item,index) in hostList" :key="index">
                <div class="node-header">
                <span class="node-id">节点ID: {{ item.nodeId }}</span>
               </div>
               <div class="node-divider"></div>
               <div class="node-content">
              <div class="node-info">
                <div class="info-grid">
                  <div class="info-item">
                    <span class="info-label">节点类型:</span>
                    <span class="info-value real-node">宿主机</span>
                  </div>
                  <div class="info-item" v-for="(_,key) in hostListItems" :key="key">
                    <span class="info-label">{{ hostListItems[key] }}:</span>
                    <span class="info-value">{{ item[key] }}</span>
                  </div>
                </div>
                <div class="status-indicator" :class="item.connectionStatus === 1 ? 'connected' : 'disconnected'">
                  <img :src="item.imgUrl" alt="" class="status-icon">
                  <div class="status-pulse"></div>
                  <div class="status-text">{{ item.connectionStatus === 1 ? '已连接' : '未连接' }}</div>
                </div>
              </div>
              <div class="node-actions">
                <div class="global_btn" v-globalBtnLoading="{ handler: handleViewVirtualNode.bind(null,item), text: '查看中...' }">查看虚拟节点</div>
                <div class="global_btn"  @click="handleAddVirtualNode(item)">创建虚拟节点</div>
              </div>
            </div>
               </div>
            </div>
        </MCard>
        <MCard>
            <template #header>
                <div class="flex gap-20px items-center">
                    <span>宿主机{{currentHost?.nodeId}}虚拟节点信息</span>
                   <el-radio-group v-model="nodeChooseConfig.nodeTypeRadio" @change="handleTypeChange">
            <el-radio value="1" size="large">已连接</el-radio>
          <el-radio value="0" size="large">未连接</el-radio>
          <el-radio value="2" size="large">全部</el-radio>
          </el-radio-group>
                </div>
            </template>
            <div class="flex gap-10px items-center">
         <div class="global_btn" v-globalBtnLoading="{ handler: handleStartVirtualNode, text: '启动中...' }">一键启动</div>
         <div class="global_btn" v-globalBtnLoading="{ handler: handleStopVirtualNode, text: '停止中...' }">一键停止</div>
         <div class="global_btn" v-globalBtnLoading="{ handler: handleDeleteVirtualNode, text: '删除中...' }">一键删除</div>
         <div class="tech-checkbox" @click="toggleSelectAll">
           <div class="checkbox-inner" :class="{'is-checked': nodeChooseConfig.isSelectAll}">
             <div class="check-mark" v-if="nodeChooseConfig.isSelectAll"></div>
           </div>
           <span class="checkbox-label">全选</span>
         </div>
            </div>
            <div class="grid grid-cols-4 gap-10px m-t-20px">
        <div class="deployedNodeItem" v-for="(item,index) in virtualNodeList" :key="index">
            <div class="node-header">
              <div class="tech-checkbox" @click="toggleItemSelect(item)">
                <div class="checkbox-inner" :class="{'is-checked': item.isSelect}">
                  <div class="check-mark" v-if="item.isSelect"></div>
                </div>
              </div>
              <span class="node-id">节点ID: {{ item.nodeId }}</span>
            </div>
            <div class="node-divider"></div>
            <div class="node-content">
              <div class="node-info">
                <div class="info-grid">
                  <div class="info-item">
                    <span class="info-label">节点类型:</span>
                    <span class="info-value" :class="item.type===1 ? 'real-node' : 'virtual-node'">{{ item.type===1 ? '真实节点' : '虚拟节点' }}</span>
                  </div>
                  <div class="info-item" v-for="(_,key) in virtualNodeListItems" :key="key">
                    <span class="info-label">{{ virtualNodeListItems[key] }}:</span>
                    <span class="info-value">{{ item[key] }}</span>
                  </div>
                </div>
                <div class="status-indicator" :class="item.connectionStatus === 1 ? 'connected' : 'disconnected'">
                  <img :src="item.imgUrl" alt="" class="status-icon">
                  <div class="status-pulse"></div>
                  <div class="status-text">{{ item.connectionStatus === 1 ? '已连接' : '未连接' }}</div>
                </div>
              </div>
              <div class="node-actions">            
              </div>
            </div>
        </div>
            </div>
            <div class="flex justify-center m-t-20px">
            <el-pagination
            v-model:currentPage="pageData.currentPage"
            v-model:page-size="pageData.pageSize"
            :page-sizes="[3,5,7,10]"
            layout="total, prev, pager, next, jumper"
            :total="pageData.total"
            @size-change="handleViewVirtualNode"
            @current-change="handleViewVirtualNode"
            size="small"
           />
      </div>
        </MCard>
        <MDrawer
          v-bind="addVirtualNodeDialogData"
          v-model:modelValue="addVirtualNodeDialogData.visible"
          @close="handleCloseAddVirtualNodeDialog"
        >   
          <template #content>
            <div>
             <el-steps  :active="stepConfig.stepActive" >
            <el-step v-for="(item,index) in stepConfig.stepList" :key="index" :title="item.title" />
            </el-steps>
            </div>
            <div class="">
              <div v-show="stepConfig.stepActive === 1" class="m-t-20px">
               <div class="global_btn" style="width: 200px;" v-globalBtnLoading="{ handler:handleConfigurationIP, text: '配置中...' }">分配子网IP</div>
            </div>
            <div v-show="stepConfig.stepActive === 2" class="m-t-20px ">
              <el-form 
            :inline="true"
            :model="addVirtualNodeForm" 
            ref="addVirtualNodeFormRef" 
            :rules="addVirtualNodeFormRules" 
            labelPosition="left"
            labelWidth="120px"
            >
            <el-form-item label="虚拟节点数量" prop="virtualNodeNum">
              <el-input style="width: 120px;" v-model="addVirtualNodeForm.virtualNodeNum" />
            </el-form-item>
            <el-form-item>
            <div class="global_btn"   v-globalBtnLoading="{ handler: handleQueryAvailableSubnetIP, text: '查询中...' }">查询可用子网</div>     
            </el-form-item>
            </el-form>   
             <div class="flex gap-10px items-center" v-show="paginatedSubnetList.length > 0">
              <div 
              class="global_btn" 
              v-globalBtnLoading="{ handler: handleSaveSubnet, text: '验证中...' }" 
              
              >
              验证是否可用
              </div>
              <div class="global_btn" v-globalBtnLoading="{ handler: handleBatchModifySubnet, text: '修改中...' }">批量修改子网ipv4和ipv6</div>
              <div class="global_btn" v-globalBtnLoading="{ handler: handleCreateVirtualNode, text: '下发中...' }" >下发子网ipv4和ipv6</div>
             </div>
              <div class="p-b-20px subnet-container">
                <div class="subnet-card-container">
                  <div class="subnet-card" 
                    v-for="(item, index) in paginatedSubnetList" 
                    :key="index"
                    :class="{
                      'subnet-card-available': item.isVerified && (item.ipv4Status === 1 || item.ipv6Status === 1),
                      'subnet-card-unavailable': item.isVerified && (item.ipv4Status !== 1 || item.ipv6Status !== 1)
                    }"
                  >
                    <div class="subnet-card-header">
                      <div class="tech-checkbox" @click="toggleItemSelectIpv(item)">
                    <div class="checkbox-inner" :class="{'is-checked': item.isSelect}">
                      <div class="check-mark" v-if="item.isSelect"></div>
                    </div>
                    </div>
                      <span class="subnet-card-title">子网 #{{ index + 1 + (subnetPageData.currentPage - 1) * subnetPageData.pageSize }}</span>
                      <div class="subnet-card-actions">
                        <el-button 
                          type="primary" 
                          size="small" 
                          @click="toggleEditMode(item)"
                          circle
                        >
                          <el-icon>
                            <component :is="item.editing ? 'Check' : 'Edit'" />
                          </el-icon>
                        </el-button>
                      </div>
                    </div>
                    <div class="subnet-card-content">
                      <div class="subnet-card-item">
                        <span class="subnet-card-label">IPv4:</span>
                        <div class="subnet-card-value-container">
                          <el-input 
                            v-if="item.editing" 
                            v-model="item.ip" 
                            size="small"
                          ></el-input>
                          <span v-else class="subnet-card-value">{{ item.ip }}</span>
                        </div>
                      </div>
                      <div class="subnet-card-item">
                        <span class="subnet-card-label">IPv6:</span>
                        <div class="subnet-card-value-container">
                          <el-input 
                            v-if="item.editing" 
                            v-model="item.ipv6" 
                            size="small"
                          ></el-input>
                          <span v-else class="subnet-card-value">{{ item.ipv6 }}</span>
                        </div>
                      </div>
                      <div class=""  v-if="item.isVerified">                    
                          <div class="m-b-10px">
                            <span class="subnet-card-label">IPv4可用状态: </span>
                            <span class="subnet-card-value" :class="{'status-available': item.ipv4Status === 1, 'status-unavailable': item.ipv4Status !== 1}">{{ item.ipv4Status === 1 ? '可用' : '不可用' }}</span>
                          </div>
                          <div>
                            <span class="subnet-card-label">IPv6可用状态: </span>
                            <span class="subnet-card-value" :class="{'status-available': item.ipv6Status === 1, 'status-unavailable': item.ipv6Status !== 1}">{{ item.ipv6Status === 1 ? '可用' : '不可用' }}</span>
                          </div>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="flex justify-center m-t-20px" v-if="availableSubnetIPList.length > 0">
                  <el-pagination
                    v-model:current-page="subnetPageData.currentPage"
                    v-model:page-size="subnetPageData.pageSize"
                    :page-sizes="[4, 8, 12, 16]"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="availableSubnetIPList.length"
                    @size-change="handleSubnetPageSizeChange"
                    @current-change="handleSubnetPageChange"
                    size="small"
                  />
                </div>
              </div>
            </div>
            </div>         
          </template>    
        </MDrawer>
        <Mprogress 
      :show="virtualNodeProgress.showProgress"
      :progress="virtualNodeProgress.progress"
      :title="virtualNodeProgress.title"
      :progressText="virtualNodeProgress.progressText"
      :waitingText="virtualNodeProgress.waitingText"
      :completeText="virtualNodeProgress.completeText"
      :primaryColor="virtualNodeProgress.primaryColor"
      @close="virtualNodeProgress.showProgress = false"
         />
    </div>
  </template>
<script lang="ts">
  import { defineComponent } from 'vue'
  export default defineComponent({
    name: 'SimulationPlatform',
  })
</script>
  
<script setup  lang="ts">
import {nodeManagementApi} from '@/api/nodeManagement'
import { deployPlatformApi } from '@/api/deployPlatform'
import { virtualNodeApi } from '@/api/virtualNode'
import connectedImg from "@/assets/imgs/connected.png"
import disconnectedImg from "@/assets/imgs/disconnected.png"
import { ElNotificationFn } from "@/utils/computedUtils"
import { getWebSocketInstance } from "@/utils/websocketExample"
import { networkApi } from '@/api/network'
import { Check, Edit } from '@element-plus/icons-vue'
import { computed } from 'vue'
const wsClient = getWebSocketInstance()
const hostList = ref<any[]>([])
const hostListItems = ref<any>({
  ipAddress:"IP地址",
  virtualNodeNum:"虚拟节点个数"
})
const deploymentOptions = ref<any>({
  options:[ ],
  placeholder:"选择部署平台",
  width:"200px"
})
async function getNodeList(){
  try {
    const res = await nodeManagementApi.postNodeConditionQuery({
       type:2
    })
    hostList.value = res.data.map((item:any)=>{
      return {
        ...item,
        imgUrl:item.connectionStatus=== 1 ? connectedImg : disconnectedImg,
      }
    })
    currentHost.value = hostList.value[0]
    hostList.value.forEach((item:any)=>{
      getVirtualNodeNum(item)
    })
    handleViewVirtualNode()
  } catch (error) { }
}
async function getVirtualNodeNum(item:any){
  try {
    const {data} = await virtualNodeApi.getVirtualNodeNum({
      nodeId:item.nodeId,
      ipAddress:item.ipAddress
    })
    item.virtualNodeNum = data
  } catch (error) { }
}
const pageData = ref<any>({
  currentPage:1,
  pageSize:8,
  total:0
})
const currentHost = ref<any>(null)
const virtualNodeList = ref<any[]>([])
const initialVirtualNodeList = ref<any[]>([])
  const nodeChooseConfig = ref<any>({
  nodeTypeRadio:"2",
  isSelectAll:false
})
const virtualNodeListItems = ref<any>({
  ipAddress:"IP地址",
  updateTime:"更新时间",
})
async function handleViewVirtualNode(item?:any){
   try {   
     if(item && typeof item == "object"){
      currentHost.value = item
     }
    const { data} = await virtualNodeApi.getVirtualNodeByHostIdAndIp({
      nodeId:currentHost.value.nodeId,
      ipAddress:currentHost.value.ipAddress,
      currentPage:pageData.value.currentPage,
      pageSize:pageData.value.pageSize
    })
    initialVirtualNodeList.value = data.records.map((item:any)=>{
      return {
        ...item,
        imgUrl:item.connectionStatus=== 1 ? connectedImg : disconnectedImg,
        isSelect:false
      }
    }) 

    if(nodeChooseConfig.value.nodeTypeRadio == "0"||nodeChooseConfig.value.nodeTypeRadio == "1"){
      virtualNodeList.value = initialVirtualNodeList.value.filter((item:any)=>{
        return item.connectionStatus == nodeChooseConfig.value.nodeTypeRadio
      })
    }else{
      virtualNodeList.value = initialVirtualNodeList.value
    }
    pageData.value.total = data.total
   } catch (error) {}
}
function handleTypeChange(val:string | number | boolean | undefined){ 
  if(val === "2"){
    virtualNodeList.value = initialVirtualNodeList.value
    return
  }
  virtualNodeList.value = initialVirtualNodeList.value.filter((item:any)=>{
    return item.connectionStatus == val
  })
}
function toggleItemSelect(item:any){
  item.isSelect = !item.isSelect
  nodeChooseConfig.value.isSelectAll = virtualNodeList.value.every((node:any)=>node.isSelect)
}
function toggleSelectAll(){
  virtualNodeList.value.forEach((item:any)=>{
    item.isSelect = !nodeChooseConfig.value.isSelectAll
  })
  nodeChooseConfig.value.isSelectAll = !nodeChooseConfig.value.isSelectAll
}
async function handleAddVirtualNode(item:any){
  try {
    addVirtualNodeDialogData.value.visible = true
    addVirtualNodeForm.value.nodeId = item.nodeId
    addVirtualNodeForm.value.ipAddress = item.ipAddress
    addVirtualNodeForm.value.configStatus = item.configStatus
    stepConfig.value.stepActive = 1
    const {data} = await deployPlatformApi.getDeployPlatformListByCondition({})
    deploymentOptions.value.options = data.map((item:any)=>{
      return {
        label:item.deploymentName,
        value:item.deploymentId 
      }
    })
  } catch (error) {}
}
const addVirtualNodeDialogData = ref<any>({
    visible:false,
    title:'创建虚拟节点',
    nodeId:"",
    direction:"rtl",
    size:"50%"
})
const addVirtualNodeForm = ref<any>({
  deploymentName:"",
  virtualNodeNum:"",
  ipAddress:"",
  nodeId:"",
  configStatus:0
})
const addVirtualNodeFormRules = ref<any>({
  deploymentName:[{required:true,message:'选择部署平台',trigger:'blur'}],
  virtualNodeNum:[{required:true,message:'输入虚拟节点数量',trigger:'blur'}],
})
const addVirtualNodeFormRef = ref<any>(null)

const availableSubnetIPList = ref<any[]>([])  // 保存查询到的子网列表
const modifiedSubnetList = ref<any[]>([]) // 保存修改后的子网列表
const subnetPageData = ref<any>({
  currentPage: 1,
  pageSize: 8,
  total: 0
})
// 计算分页后的子网列表
const paginatedSubnetList = computed(() => {
  const start = (subnetPageData.value.currentPage - 1) * subnetPageData.value.pageSize
  const end = start + subnetPageData.value.pageSize
  return availableSubnetIPList.value.slice(start, end)
})
// 子网分页处理函数
function handleSubnetPageSizeChange(size: number) {
  subnetPageData.value.pageSize = size
}
function handleSubnetPageChange(page: number) {
  subnetPageData.value.currentPage = page
}
async function handleQueryAvailableSubnetIP(){
  try {
    const {data} = await networkApi.getAvailableSubnetIPList({
      virtualServerIp:addVirtualNodeForm.value.ipAddress,
      number:Number(addVirtualNodeForm.value.virtualNodeNum)
    })
    availableSubnetIPList.value = data.map((item: any) => ({
      ...item,
      editing: false,
      originalIp: item.ip,
      originalIpv6: item.ipv6,
      ipv4Status:2,
      ipv6Status:2,
      isVerified:false,
      isSelect:false
    }))
    subnetPageData.value.total = availableSubnetIPList.value.length
    subnetPageData.value.currentPage = 1
  } catch (error) { }
}
function toggleEditMode(item: any) {
  if (item.editing) {
    saveSubnetChanges(item);
  } else {
    item.editing = true;
    item.originalIp = item.ip;
    item.originalIpv6 = item.ipv6;
  }
}
async function saveSubnetChanges(item: any) {
    item.editing = false;
}
function toggleItemSelectIpv(item:any){
  item.isSelect = !item.isSelect 
}
async function handleSaveSubnet(){
  try {
    const list = paginatedSubnetList.value.filter((item:any)=>item.isSelect)
    if(list.length === 0){
      ElNotificationFn("warning","至少选择一个子网")
      return
    }
    const {data} = await networkApi.verifySubnetIP(list)
    //根据返回结果,在modifiedSubnetList中找到对应的item,并修改其status
    paginatedSubnetList.value.forEach((item:any)=>{
      const result = data.find((resultItem:any)=>resultItem.netConfId=== item.netConfId)
      if(result){
        item.ipv4Status = result.ipv4Status
        item.ipv6Status = result.ipv6Status
        item.isVerified = true
      }
    })
  } catch (error) { }
}
async function handleBatchModifySubnet(){
  try {
    let list = paginatedSubnetList.value.filter((item:any)=>item.isSelect)
    if(list.length === 0){
      ElNotificationFn("warning","至少选择一个子网")
      return
    }
    list = list.filter((item:any)=>item.ipv4Status === 1 && item.ipv6Status === 1)
    if(list.length === 0){
      ElNotificationFn("warning","没有可用的子网")
      return
    }
    await networkApi.modifySubnetIP(list)
    ElNotificationFn("success","批量修改子网ipv4和ipv6成功")
  } catch (error) { }
}
async function handleCreateVirtualNode(){
   try {
    const availableSubnetList = availableSubnetIPList.value.filter((item:any)=>item.ipv4Status === 0 ||item.ipv6Status === 0)
    if(availableSubnetList.length){
      ElNotificationFn("warning","有子网未验证")
      return
    }
    await addVirtualNodeFormRef.value.validate()
    await virtualNodeApi.createVirtualNode({
      nodeId:addVirtualNodeForm.value.nodeId,
      virtualNodeNum:addVirtualNodeForm.value.virtualNodeNum,
      subnetList:availableSubnetIPList.value
    })
    virtualNodeProgress.value.showProgress = true
    const textConfig = commandTextConfig["JRLC.run.in.container.app"]
    virtualNodeProgress.value.title = textConfig.title
    virtualNodeProgress.value.progressText = textConfig.progressText
    virtualNodeProgress.value.waitingText = textConfig.waitingText
    virtualNodeProgress.value.completeText = textConfig.completeText
    virtualNodeProgress.value.showProgress = true
   } catch (error) { }
}
function handleCloseAddVirtualNodeDialog(){
  availableSubnetIPList.value = []
  subnetPageData.value.currentPage = 1
  subnetPageData.value.total = 0
}
async function handleStopVirtualNode(){
   try {
    if(virtualNodeList.value.every((item:any)=>!item.isSelect)){
      ElNotificationFn("warning","至少选择一个虚拟节点")
      return
    }
    // 只能停止已连接的节点
    if(virtualNodeList.value.some((item:any)=>item.isSelect && item.connectionStatus === 0)){
      ElNotificationFn("warning","只能停止已连接的虚拟节点")
      return
    }
    const ips = virtualNodeList.value.filter((item:any)=>item.isSelect && item.connectionStatus === 1).map((item:any)=>item.ipAddress)
    await virtualNodeApi.stopVirtualNode({
      ips:ips
    })
    // 更新进度条文本为停止相关文本
    const textConfig = commandTextConfig["JRLC.stop.in.container.app"]
    virtualNodeProgress.value.title = textConfig.title
    virtualNodeProgress.value.progressText = textConfig.progressText
    virtualNodeProgress.value.waitingText = textConfig.waitingText
    virtualNodeProgress.value.completeText = textConfig.completeText
    virtualNodeProgress.value.showProgress = true
   } catch (error) {}
}
async function handleDeleteVirtualNode(){
   try {
    if(virtualNodeList.value.every((item:any)=>!item.isSelect)){
      ElNotificationFn("warning","至少选择一个虚拟节点")
      return
    }  
    if(virtualNodeList.value.some((item:any)=>item.isSelect && item.connectionStatus === 1)){
      ElNotificationFn("warning","只能删除未连接的虚拟节点")
      return
    }
    // 确保虚拟节点可以被删除（此处可能需要添加业务逻辑判断条件）
    const ips = virtualNodeList.value.filter((item:any)=>item.isSelect).map((item:any)=>item.ipAddress)
    await virtualNodeApi.deleteVirtualNode({
      ips:ips
    })
    // 更新进度条文本为删除相关文本
    const textConfig = commandTextConfig["JRLC.delete.in.container.app"]
    virtualNodeProgress.value.title = textConfig.title
    virtualNodeProgress.value.progressText = textConfig.progressText
    virtualNodeProgress.value.waitingText = textConfig.waitingText
    virtualNodeProgress.value.completeText = textConfig.completeText
    virtualNodeProgress.value.showProgress = true
   } catch (error) { }
}
const virtualNodeProgress = ref<any>({
  showProgress:false,
  progress:0,
  title:"",
  progressText:"",
  waitingText:"",
  completeText:"",
  primaryColor:""
})
// 命令对应的文字配置
interface CommandTextConfigType {
  title: string;
  progressText: string;
  waitingText: string;
  completeText: string;
  actionText: string;
  errorText: string;
}
interface CommandTextMapType {
  [key: string]: CommandTextConfigType;
}
const commandTextConfig: CommandTextMapType = {
  "JRLC.run.in.container.app": {
    title: "创建虚拟节点",
    progressText: "正在创建虚拟节点列表",
    waitingText: "耐心等待，创建完成后将自动更新...",
    completeText: "创建完成，即将更新...",
    actionText: "创建",
    errorText: "创建失败"
  },
  "JRLC.start.in.container.app": {
    title: "启动虚拟节点",
    progressText: "正在启动虚拟节点列表",
    waitingText: "耐心等待，启动完成后将自动保存...",
    completeText: "启动完成，即将保存...",
    actionText: "启动",
    errorText: "启动失败"
  },
  "JRLC.stop.in.container.app": {
    title: "停止虚拟节点",
    progressText: "正在停止虚拟节点列表",
    waitingText: "耐心等待，停止完成后将自动更新...",
    completeText: "停止完成，即将更新...",
    actionText: "停止",
    errorText: "停止失败"
  },
  "JRLC.delete.in.container.app": {
    title: "删除虚拟节点",
    progressText: "正在删除虚拟节点列表",
    waitingText: "耐心等待，删除完成后将自动更新...",
    completeText: "删除完成，即将更新...",
    actionText: "删除",
    errorText: "删除失败"
  },
}
async function handleStartVirtualNode(){
  try {
    if(virtualNodeList.value.every((item:any)=>!item.isSelect)){
      ElNotificationFn("warning","至少选择一个虚拟节点")
      return
    }
    // 只能启动未连接的节点
    if(virtualNodeList.value.some((item:any)=>item.isSelect && item.connectionStatus === 1)){
      ElNotificationFn("warning","只能启动未连接的虚拟节点")
      return
    }
    const ips = virtualNodeList.value.filter((item:any)=>item.isSelect && item.connectionStatus === 0).map((item:any)=>item.ipAddress)
    await virtualNodeApi.startVirtualNode({
      ips:ips
    })
    virtualNodeProgress.value.showProgress = true
    const textConfig = commandTextConfig["JRLC.start.in.container.app"]
    virtualNodeProgress.value.title = textConfig.title
    virtualNodeProgress.value.progressText = textConfig.progressText
    virtualNodeProgress.value.waitingText = textConfig.waitingText
    virtualNodeProgress.value.completeText = textConfig.completeText
    virtualNodeProgress.value.showProgress = true
  } catch (error) { } 
}
function handleInContainer(data:any, cmd:string){
  // 如果没有数据，直接返回
  if (!data) return
  // 获取对应命令的文字配置
  const textConfig = commandTextConfig[cmd] || commandTextConfig["JRLC.run.in.container.app"]
  // 获取已选择的IP列表
  let selectedIps = []
  if(cmd == "JRLC.start.in.container.app"){
    selectedIps = virtualNodeList.value
      .filter((item:any) => item.isSelect && item.connectionStatus === 0)
      .map((item:any) => item.ipAddress)
  }else if(cmd == "JRLC.stop.in.container.app"){
    selectedIps = virtualNodeList.value
      .filter((item:any) => item.isSelect && item.connectionStatus === 1)
      .map((item:any) => item.ipAddress)
  }else if(cmd == "JRLC.delete.in.container.app"){
    selectedIps = virtualNodeList.value
      .filter((item:any) => item.isSelect)
      .map((item:any) => item.ipAddress)
  }
  const totalIps = selectedIps.length
  // 处理成功状态更新
  if (data.status === 'success') {
    // 成功计数加1
    successCount.value++
    // 计算进度
    const progressPercent = Math.floor((successCount.value / totalIps) * 100)
    // 更新进度条状态
    virtualNodeProgress.value.title = textConfig.title
    virtualNodeProgress.value.progress = progressPercent
    virtualNodeProgress.value.progressText = `${textConfig.progressText} (${successCount.value}/${totalIps})`
    virtualNodeProgress.value.waitingText = textConfig.waitingText
    virtualNodeProgress.value.completeText = textConfig.completeText
    virtualNodeProgress.value.showProgress = true   
    // 如果有对应的IP，则在提示中显示
    const currentIp = selectedIps[successCount.value - 1] || ""
    ElNotificationFn("success", `${textConfig.title}${currentIp ? currentIp : `第${successCount.value}个节点`}成功`)
  } 
  // 处理节点执行失败的情况
  else if (data.status === 'failed') {
    // 失败计数仍然增加，保持总进度一致
    successCount.value++
    // 计算当前进度
    const progressPercent = Math.floor((successCount.value / totalIps) * 100)
    // 更新进度条状态，但标记有错误
    virtualNodeProgress.value.title = textConfig.title
    virtualNodeProgress.value.progress = progressPercent
    virtualNodeProgress.value.progressText = `${textConfig.progressText} (${successCount.value}/${totalIps}) - 有错误`
    virtualNodeProgress.value.waitingText = textConfig.waitingText
    virtualNodeProgress.value.completeText = textConfig.completeText
    virtualNodeProgress.value.showProgress = true
    // 如果有对应的IP，则在提示中显示
    const currentIp = selectedIps[successCount.value - 1] || ""
    ElNotificationFn("error", `${textConfig.title}${currentIp ? currentIp : `第${successCount.value}个节点`}失败`)
  }
  // 处理结束状态
  if (data.status === 'end') {
    // 设置进度为100%完成
    virtualNodeProgress.value.progress = 100
    virtualNodeProgress.value.progressText = virtualNodeProgress.value.completeText
    // 延迟关闭进度条并重置状态
    setTimeout(() => {
      virtualNodeProgress.value.showProgress = false
      // 重置进度条和计数器
      virtualNodeProgress.value.progress = 0
      virtualNodeProgress.value.progressText = textConfig.progressText
      successCount.value = 0
      // 刷新节点列表
      getNodeList()
    }, 1500)
  }
}
const stepConfig = ref<any>({
   stepActive:1,
   stepList:[
    {
      title:"配置子网IP",
    },
    {
      title:"配置虚拟节点",
    }  
   ]
})
async function handleConfigurationIP(){
  if(addVirtualNodeForm.value.configStatus == 1){
    stepConfig.value.stepActive = 2
    return
  }
  await networkApi.getNetworkList({
    virtualServerIp:addVirtualNodeForm.value.ipAddress
  })
  stepConfig.value.stepActive = 2
}
const wsResponseHandlers:any = {
  "JRLC.start.in.container.app":{
    handler:(data:any) => handleInContainer(data, "JRLC.start.in.container.app")
  },
  "JRLC.stop.in.container.app":{
    handler:(data:any) => handleInContainer(data, "JRLC.stop.in.container.app")
  },
  "JRLC.delete.in.container.app":{
    handler:(data:any) => handleInContainer(data, "JRLC.delete.in.container.app")
  },
  "JRLC.run.in.container.app":{
    handler:(data:any) =>wsResponseCreateVirtualNode(data)
  }
}
const successCount = ref<number>(0)
  function wsResponseCreateVirtualNode(data:any){
    if(!data) return
    const total = addVirtualNodeForm.value.virtualNodeNum
    const textConfig = commandTextConfig["JRLC.run.in.container.app"]
    if(data.status == "success"){
      successCount.value++
      const progressPercent = Math.floor((successCount.value / total) * 100)
      virtualNodeProgress.value.progress = progressPercent
      // 直接设置文本，而不是追加
      virtualNodeProgress.value.progressText = `${textConfig.progressText} (${successCount.value}/${total})`
      ElNotificationFn("success", `创建虚拟节点成功 ${successCount.value}/${total}`)
    }else if(data.status == "failed"){
      successCount.value++
      const progressPercent = Math.floor((successCount.value / total) * 100)
      virtualNodeProgress.value.progress = progressPercent
      // 直接设置文本，而不是追加
      virtualNodeProgress.value.progressText = `${textConfig.progressText} (${successCount.value}/${total}) - 有错误`
      ElNotificationFn("error", `创建虚拟节点失败 ${successCount.value}/${total}`)
    }
    if(data.status == "end"){
      virtualNodeProgress.value.progress = 100
      virtualNodeProgress.value.progressText = virtualNodeProgress.value.completeText
      setTimeout(() => {
        virtualNodeProgress.value.showProgress = false
        virtualNodeProgress.value.progress = 0
        successCount.value = 0
        getNodeList()
        // 关闭弹窗
        addVirtualNodeDialogData.value.visible = false
        // 重置步骤
        stepConfig.value.stepActive = 1
      }, 1500)
    }
}
wsClient.on('message',(resPonse:any)=>{
  const {cmd,data} = resPonse
  if(!Object.keys(wsResponseHandlers).includes(cmd)) return
  wsResponseHandlers[cmd].handler(data)
})
onMounted(()=>{
    getNodeList()
})
</script>
  
<style  lang="scss" scoped>
@import "@/styles/card.scss";
@import "@/styles/pagination.scss";
@import "@/styles/input.scss";
@import "@/styles/form.scss";
@import "@/styles/table.scss";
  .simulationPlatform-container{
    width: 100%;
    height: 100%;
    .deployedNodeItem {
  background: linear-gradient(
    180deg, 
    rgba(22, 30, 45, 0.8) 0%, 
    rgba(18, 28, 40, 0.85) 50%, 
    rgba(15, 25, 38, 0.8) 100%
  );
  border: 1px solid rgba(35, 85, 140, 0.5);
  border-radius: 4px;
  box-shadow: 
    inset 0 0 15px rgba(0, 140, 255, 0.08),
    0 0 10px rgba(0, 0, 0, 0.4),
    0 0 8px rgba(0, 150, 255, 0.1);
  overflow: hidden;
  position: relative;
  transition: all 0.3s ease;
  
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(90deg, 
      transparent, 
      rgba(0, 170, 255, 0.5), 
      transparent
    );
    opacity: 0.7;
    z-index: 2;
  }
  
  &::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-image: 
      linear-gradient(rgba(40, 100, 180, 0.02) 1px, transparent 1px),
      linear-gradient(90deg, rgba(40, 100, 180, 0.02) 1px, transparent 1px);
    background-size: 20px 20px;
    pointer-events: none;
    opacity: 0.5;
    z-index: 1;
  }
  
  &:hover {
    transform: translateY(-2px);
    box-shadow: 
      inset 0 0 20px rgba(0, 140, 255, 0.12),
      0 5px 15px rgba(0, 0, 0, 0.4),
      0 0 15px rgba(0, 150, 255, 0.15);
    
    .node-id {
      color: #fff;
      text-shadow: 0 0 8px rgba(0, 180, 255, 0.6);
    }
    
    .node-divider {
      background: linear-gradient(90deg, 
        transparent, 
        rgba(0, 180, 255, 0.6), 
        transparent
      );
      box-shadow: 0 0 8px rgba(0, 180, 255, 0.4);
    }
  }
  
  .node-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px;
    position: relative;
    z-index: 2;
  }
  
  .node-id {
    color: rgba(255, 255, 255, 0.9);
    font-family: 'Consolas', monospace;
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.5px;
    text-shadow: 0 0 5px rgba(0, 140, 255, 0.3);
    transition: all 0.3s;
  }
  
  .node-divider {
    height: 1px;
    width: 90%;
    margin: 0 auto;
    background: linear-gradient(90deg, 
      transparent, 
      rgba(0, 150, 255, 0.4), 
      transparent
    );
    transition: all 0.3s;
  }
  
  .node-content {
    padding: 12px;
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 15px;
  }
  
  .node-info {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  .info-grid {
    display: grid;
    gap: 8px;
  }
  
  .info-item {
    display: flex;
    align-items: center;
    gap: 8px; 
    .real-node {
      color: rgba(0, 255, 80, 0.9);
      text-shadow: 
        0 0 5px rgba(0, 255, 80, 0.5),
        0 0 10px rgba(0, 255, 80, 0.3);
      font-weight: 500;
      letter-spacing: 0.5px;
      position: relative;
      padding-left: 15px;
    } 
    .virtual-node {
      color: rgba(255, 80, 80, 0.9);
      text-shadow: 
        0 0 5px rgba(255, 80, 80, 0.5),
        0 0 10px rgba(255, 80, 80, 0.3);
      font-weight: 500;
      letter-spacing: 0.5px;
      position: relative;
      padding-left: 15px;
    }
  }
  
  .info-label {
    color: rgba(100, 180, 255, 0.9);
    font-size: 13px;
    font-weight: 500;
  }
  
  .info-value {
    color: rgba(255, 255, 255, 0.85);
    font-size: 13px;
    font-family: 'Consolas', monospace;
  }
  .info-value {
  color: #ffffff;
  font-size: 15px;
  font-family: 'Consolas', monospace;
  letter-spacing: 0.5px;
  padding-left: 14px;
  position: relative;
  text-shadow: 0 0 5px rgba(0, 180, 255, 0.3);
  transition: all 0.3s;
  
  &::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 8px;
    height: 1px;
    background: rgba(0, 180, 255, 0.5);
  }
}
  
  .status-indicator {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    position: relative;
    width: 50px;
    height: 50px;
    
    &.connected {
      .status-icon {
        filter: drop-shadow(0 0 3px #00ff4c);
      }    
      /* .status-pulse {
        border: 2px solid rgba(0, 255, 76, 0.7);
        animation: pulse-green 2s infinite;
      }  */
      .status-text {
        color: #01AA78; 
      }
    }   
    &.disconnected {
      .status-icon {
        filter: drop-shadow(0 0 3px #ff4545);
      }      
    /*   .status-pulse {
        border: 2px solid rgba(255, 69, 69, 0.7);
        animation: pulse-red 2s infinite;
      }      */
      .status-text {
        color: #DD675E;
      }
    }
  }
  
  .status-icon {
    width: 24px;
    height: 24px;
    position: relative;
    z-index: 2;
    margin-bottom: 5px;
  }
  
  .status-text {
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.5px;
    font-family: 'Consolas', monospace;
    position: relative;
    z-index: 2;
    white-space: nowrap;
  }
  
  .status-pulse {
    position: absolute;
    top: 12px; /* 调整位置以匹配图标 */
    left: 50%;
    transform: translate(-50%, -50%);
    width: 30px;
    height: 30px;
    border-radius: 50%;
    opacity: 0;
  }
  
  .node-actions {
    display: flex;
    gap: 10px;
    margin-top: 5px;
  }
  }
  }


  /* 子网卡片样式 */
  .subnet-card-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
    gap: 16px;
    margin-top: 16px;
  }

  .subnet-card {
    background: linear-gradient(
      180deg, 
      rgba(22, 30, 45, 0.8) 0%, 
      rgba(18, 28, 40, 0.85) 50%, 
      rgba(15, 25, 38, 0.8) 100%
    );
    border: 1px solid rgba(35, 85, 140, 0.5);
    border-radius: 8px;
    box-shadow: 
      inset 0 0 15px rgba(0, 140, 255, 0.08),
      0 0 10px rgba(0, 0, 0, 0.4),
      0 0 8px rgba(0, 150, 255, 0.1);
    overflow: hidden;
    transition: all 0.3s ease;
    
    &:hover {
      transform: translateY(-2px);
      box-shadow: 
        inset 0 0 20px rgba(0, 140, 255, 0.12),
        0 5px 15px rgba(0, 0, 0, 0.4),
        0 0 15px rgba(0, 150, 255, 0.15);
    }
  }

  /* 根据IP可用状态添加不同颜色的边框和阴影 */
  .subnet-card-available {
    box-shadow: 
      inset 0 0 15px rgba(0, 255, 76, 0.08),
      0 0 10px rgba(0, 0, 0, 0.4),
      0 0 12px rgba(0, 255, 76, 0.2) !important;
    border: 1px solid rgba(0, 255, 76, 0.5) !important;
  }

  .subnet-card-unavailable {
    box-shadow: 
      inset 0 0 15px rgba(255, 50, 50, 0.08),
      0 0 10px rgba(0, 0, 0, 0.4),
      0 0 12px rgba(255, 50, 50, 0.2) !important;
    border: 1px solid rgba(255, 50, 50, 0.5) !important;
  }

  /* 单独设置状态文本的样式 */
  .status-available {
    color: rgba(0, 255, 80, 0.9) !important;
    text-shadow: 
      0 0 5px rgba(0, 255, 80, 0.5),
      0 0 10px rgba(0, 255, 80, 0.3);
    font-weight: 500;
  }

  .status-unavailable {
    color: rgba(255, 80, 80, 0.9) !important;
    text-shadow: 
      0 0 5px rgba(255, 80, 80, 0.5),
      0 0 10px rgba(255, 80, 80, 0.3);
    font-weight: 500;
  }

  /* 删除不支持的:has选择器 */
  .subnet-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 16px;
    border-bottom: 1px solid rgba(0, 150, 255, 0.2);
    position: relative;
    
    &::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 10%;
      right: 10%;
      height: 1px;
      background: linear-gradient(90deg, 
        transparent, 
        rgba(0, 180, 255, 0.6), 
        transparent
      );
    }
  }

  .subnet-card-title {
    color: rgba(255, 255, 255, 0.9);
    font-size: 16px;
    font-weight: 500;
    text-shadow: 0 0 5px rgba(0, 140, 255, 0.3);
  }

  .subnet-card-content {
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .subnet-card-item {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .subnet-card-label {
    color: rgba(100, 180, 255, 0.9);
    font-size: 14px;
    font-weight: 500;
    min-width: 60px;
  }

  .subnet-card-value-container {
    flex: 1;
  }

  .subnet-card-value {
    color: #fff;
    font-family: 'Consolas', monospace;
    font-size: 14px;
    letter-spacing: 0.5px;
  }
</style>